#define  _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/un.h>
#include <signal.h>
#include <sys/sysinfo.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/prctl.h>
#include <sys/stat.h>

#include "core.h"
#include "../config/config.h"
#include "../conn/conn.h"


void set_proctitle_unsafe(const char* new_name)
{
    extern char **environ;
    // 获取该进程的启动参数字符串
    int pid = getpid();
    char file_name[100];
    snprintf(file_name, sizeof(file_name), "/proc/%d/cmdline", pid);
    int fd = open(file_name, O_RDONLY);
    if (fd < 0)
    {
        return;
    }
    char tempCmd[512];
    long cmd_length=read(fd, tempCmd, sizeof(tempCmd));
    close(fd);

    // 获取 argv[0] 的地址
    char *argv = environ[0];
    argv = argv - cmd_length;

    int size = 0;
    // 申请新的空间存放 environ 中内容
    for ( int i=0; environ[i]; i++) {
        size += strlen(environ[i]) + 1;
    }
    char* p = (char*)malloc(size);

    char* last_argv = argv;
    last_argv = argv + cmd_length;

    for (int i = 0; environ[i]; i++) {
        if (last_argv == environ[i]) {
            size = strlen(environ[i]) + 1;
            last_argv = environ[i] + size;

            memcpy(p, environ[i], size);
            environ[i] = (char*)p;
            p += size;
        }
    }
    last_argv--;

    // 修改 argv[0] 的内容
    strncpy(argv, new_name, last_argv - argv);
    p = (argv) + strlen(argv) + 1;
    if (last_argv - p > 0) {
        memset(p, 0, last_argv - p);
    }
}


// 执行一个task,成功返回pid值,失败返回-1
int execute(Task_t *task,void *pipe_handler){
    pid_t pid = fork();
    if (pid < 0){
        printf("[\033[3;31mfailed\033[0m] rinitd fork faild ->%d\n",pid);
        fflush(stdout);
        return -1;
    }else if (pid == 0){ //子进程
        if (setsid()<0)
        {
            exit(EXIT_FAILURE);
        }
        //设置stdio
        int nullfd=open("/dev/null",O_RDWR);
        char msg[1024];
        task->status.pid=getpid();
        sprintf(msg,"%s[%d]",task->service.binname,task->status.pid);
        int unix_fd=0;
        if (task->service.std_in!=NULL)
        {
            if (strcmp(task->service.std_in,"tty1")==0)
            {
                int tty=open("/dev/tty1",O_RDONLY);
                dup2(tty,STDIN_FILENO);
                close(tty);
            }else{
                dup2(nullfd,STDIN_FILENO);
            }
        }else{
            dup2(nullfd,STDIN_FILENO);
        }
        if (task->service.std_out!=NULL)
        {
             if (strcmp(task->service.std_out,"tty1")==0)
            {
                int tty=open("/dev/tty1",O_WRONLY);
                dup2(tty,STDOUT_FILENO);
                close(tty);
            }else if (strcmp(task->service.std_out,"logm")==0)
            {
                if ((unix_fd=fdhandle("/run/logm.sock",msg))>0)
                {
                    dup2(unix_fd,STDOUT_FILENO);
                }else{
                    unix_fd=nullfd;
                    dup2(unix_fd,STDOUT_FILENO);
                }
            }else{
                dup2(nullfd,STDIN_FILENO);
            }
        }else{
            dup2(nullfd,STDOUT_FILENO);
        }
        if (task->service.std_err!=NULL)
        {
            if (strcmp(task->service.std_err,"tty1")==0)
            {
                int tty=open("/dev/tty1",O_WRONLY);
                dup2(tty,STDERR_FILENO);
                close(tty);
            }else if (strcmp(task->service.std_err,"logm")==0)
            {
                dup2(unix_fd,STDERR_FILENO);   
            }   
        }else{
            dup2(nullfd,STDERR_FILENO);
        }
        if ((unix_fd > 0) && (unix_fd!=nullfd))
        {
            close(unix_fd);
        }
        close(nullfd);
        //设置signal处理信号
        signal(SIGPIPE,pipe_handler);
        //装载二进制并且执行
        if (execve(task->service.binpath,task->service.agrv,task->service.env)<0){
            exit(EXIT_FAILURE);
        }
        return 0;
    }else{  //父进程
        task->status.pid=pid;
        return pid;
    }   
}

// 监听task
int listentask(Task_t *task,void *hook){
    for (size_t i = 0; i < task->socketslen; i++)
    {
        if (task->sockets[i].stream_path!=NULL)
        {
            task->sockets[i].stream_unixfd=listen_unix(task->sockets[i].stream_path,SOCK_STREAM|SOCK_CLOEXEC,20);
            if (task->sockets[i].stream_unixfd>0)
            {
                printf("[\033[3;32m  ok  \033[0m] Listen %s -- %s[%d].\n",task->sockets[i].conf_file,task->sockets[i].stream_path,task->sockets[i].stream_unixfd);
                fflush(stdout);
            }
        }else if (task->sockets[i].dgram_path!=NULL)
        {
            task->sockets[i].dgram_unixfd=listen_unix(task->sockets[i].dgram_path,SOCK_DGRAM|SOCK_CLOEXEC,20);
            if (task->sockets[i].dgram_unixfd>0)
            {
                printf("[\033[3;32m  ok  \033[0m] Listen %s -- %s[%d].\n",task->sockets[i].conf_file,task->sockets[i].dgram_path,task->sockets[i].dgram_unixfd);
                fflush(stdout);
            }
        }  
    }
    return 0;
}

// start target
int start(Target_t *target,void *hook){
    for (size_t i = 0; i < target->taskslen; i++)
    {
        if (target->tasks[i].socketslen>0)
        {
            //printf("%d\n",target->tasks[i].socketslen);
            listentask(&target->tasks[i],NULL);
        }
        if (execute(&target->tasks[i],hook)>=0)
        {
            printf("[\033[3;32m  ok  \033[0m] Started %s -- %s[%d].\n",target->tasks[i].service.conf_file,target->tasks[i].service.binname,target->tasks[i].status.pid);
            fflush(stdout);
        }else{
            printf("[\033[3;32mfialed\033[0m] Start %s fialed -- Exec: %s.\n",target->tasks[i].service.conf_file,target->tasks[i].service.binname);
            fflush(stdout);
        }
    }
    // printf("[\033[3;32m  ok  \033[0m] Attached %s -- Task queue len=%d.\n",target->conf_file,target->taskslen);
    return 0;
}

int stopOrkill(int pid)
{
    if (kill(pid,0)<0)
    {
        return -1;
    }
    if (kill(pid,9)==0)
    {
        return 0;
    }
    return 0;
}

void terminate(Target_t *target)
{
    for (size_t i = 0; i < target->taskslen; i++)
    { 
        if (stopOrkill(target->tasks[i].status.pid)>=0)
        {
            printf("[\033[3;32m  ok  \033[0m] Stop %s -- .\n",target->tasks[i].service.conf_file);
        }  
    }
    
}

int check_alive(Target_t * target){
    for (size_t i = 0; i < target->taskslen; i++)
    {
        if (kill(target->tasks[i].status.pid,0)>=0)
        {
            return -1;
        }
    }
    return 0;
}


int check_status(Target_t * target){
    for (size_t i = 0; i < target->taskslen; i++)
    {
        if (target->tasks[i].status.ready<1)
        {
            return -1;
        }
        
    }
    return 0;
}

int target_ok(Target_t *target){
    for (size_t i = 0; i < target->taskslen; i++)
    {
        if (target->tasks[i].status.ready<1)
        {
            return -1;
        }
    }
    return 0;
}








/*
创建守护进程。常用步骤如下:
1.调用 fork 创建子进程，然后父进程退出。
2.子调用 setsid 创建新的会话和进程组，从而避免被原先的会话、进程组以及会话终端影响。
3.调用 chdir 设置工作目录。
4.调用 umask 设置文件掩码（通常设为 umask(0))。
5.关闭不需要的资源（从父进程继承的文件描述符等）。
*/
// void run_daemon(const char *dir){
//     pid_t ppid;
//     if ((ppid=fork())==0)
//     {
//         if (setsid()<0)
//         {
//             exit(-1);
//         }
//         //chdir("/");
//         //runv(dir);
//         with_logrun(dir,"/run/rinitd/stdout","/var/log/rinit.log");
//     }else if (ppid>0)
//     {
//         exit(0);
//     }else{
//         exit(-1);
//     }
// }
